package neuron.geometry;

import java.util.ArrayList;
import java.util.List;

import neuron.Coord;

public class CoordSet extends ArrayList<Coord> {

	/**
	 * 
	 */
	private static final long serialVersionUID = -772474914619410709L;

	
	/**
	 * Compute mean of coordinates
	 * @return
	 */
	public Vector3d mean()
	{
		double mx=0,my=0,mz=0;
		for (Coord c : this) {
			mx += c.x; my += c.y; mz += c.z;
		}
		mx /= this.size(); my /= this.size(); mz /= this.size();
		return new Vector3d(mx,my,mz);
	}
	
	/**
	 * Compute variance of coordinates
	 * @return
	 */
	public Vector3d var()
	{
		Vector3d mean = mean();
		
		// compute Sum[ (X - Mean) ^ 2 ]
		double mx=0,my=0,mz=0;
		for (Coord c : this) {
			mx += Math.pow(c.x - mean.x, 2);
			my += Math.pow(c.y - mean.y, 2);
			mz += Math.pow(c.z - mean.z, 2);
		}
		
		// divide by N
		mx /= this.size(); my /= this.size(); mz /= this.size();
		return new Vector3d(mx,my,mz);
	}
	
	
	
	public final static Accessor<Coord> fX = new Accessor<Coord>() {
		@Override
		public double get(Coord n) { return n.x; }
	};

	public final static Accessor<Coord> fY = new Accessor<Coord>() {
		@Override
		public double get(Coord n) { return n.y; }
	};

	public final static Accessor<Coord> fZ = new Accessor<Coord>() {
		@Override
		public double get(Coord n) { return n.z; }
	};

	
	public double maxX() { return Find.max(this, fX); }
	public double maxY() { return Find.max(this, fY); }
	public double maxZ() { return Find.max(this, fZ); }
	
	public double minX() { return Find.min(this, fX); }
	public double minY() { return Find.min(this, fY); }
	public double minZ() { return Find.min(this, fZ); }


    public interface Accessor<N> {
            public double get(N n);
    }

    public static class Find {

            public static double max(List lst, Accessor f)
            {
                    double max = Double.MIN_VALUE;
                    for (Object o : lst) {
                            double v = f.get(o);
                            if (v > max) max = v;
                    }
                    return max;
            }

            public static double min(List lst, Accessor f)
            {
                    double min = Double.MAX_VALUE;
                    for (Object o : lst) {
                            double v = f.get(o);
                            if (v < min) min = v;
                    }
                    return min;
            }

    }
}
